﻿// License: The MIT License (MIT) Copyright (c) 2011..2012 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media.Imaging;

#pragma warning disable 618

namespace GrooveSharp
{
    public class TrackInfoHelper
    {

        private static void TryTrackImage(TrackInfo info, string fileName)
        {
            if (info.Image == null && System.IO.File.Exists(fileName))
            {
                try
                {
                    info.Image = new BitmapImage(new Uri(fileName, UriKind.RelativeOrAbsolute));
                }
                catch (Exception ex)
                {
                    App.Log.ErrorFormat("Exception while loading bitmap {0}: {1}", fileName, ex.Message);
                }
            }
        }

        private static void TryTrackLargestImage(TrackInfo info, string folderName)
        {
            if (info.Image != null)
            {
                return;
            }

            long maxSize = 0;
            string largestFile = "";
            foreach (string wildcard in new List<string>() { "*.png", "*.jpg" })
            {
                foreach (string file in Directory.GetFiles(folderName, wildcard))
                {
                    long size = new FileInfo(file).Length;
                    if (size > maxSize)
                    {
                        largestFile = file;
                        maxSize = size;
                    }
                }
            }
            if (largestFile != "")
            {
                TryTrackImage(info, largestFile);
            }
        }

        public static TrackInfo GetTrackInfo(int id, string filename)
        {
            const string backslash = @"\";
            string parentFolder = Directory.GetParent(filename).ToString() + backslash;

            TrackInfo result = new TrackInfo()
                {
                    Id = id,
                    FileName = filename,
                    Image = null
                };

            using (TagLib.File tagFile = TagLib.File.Create(filename))
            {
                result.Title = GetTitle(tagFile, filename);
                result.Artist = GetArtist(tagFile, filename, false);
                result.Album = GetAlbum(tagFile, filename);
                result.Year = tagFile.Tag.Year == 0 ? "" : tagFile.Tag.Year.ToString();
                result.Genre = tagFile.Tag.FirstGenre;

                if (tagFile.Tag.Pictures.Length > 0)
                {
                    System.IO.MemoryStream stream = new System.IO.MemoryStream(tagFile.Tag.Pictures.ElementAt(0).Data.ToArray());
                    stream.Seek(0, System.IO.SeekOrigin.Begin);

                    result.Image = new BitmapImage();
                    result.Image.BeginInit();
                    result.Image.StreamSource = stream;
                    result.Image.EndInit();
                }
            }

            if (result.Image == null)
            {
                // Embedded image not found, try several files...

                // for singles...
                TryTrackImage(result, Path.ChangeExtension(filename, ".png"));
                TryTrackImage(result, Path.ChangeExtension(filename, ".jpg"));

                // for albums...
                TryTrackImage(result, parentFolder + "GrooveSharp.png");
                TryTrackImage(result, parentFolder + "GrooveSharp.jpg");
                TryTrackImage(result, parentFolder + "folder.jpg");
                TryTrackImage(result, parentFolder + "Folder.png");

                TryTrackLargestImage(result, parentFolder);
            }

            // Get things from database
            result.Rating = id <= 0
                ? 0
                : Db.SelectFirstOrDefault<int>(
                    String.Format(
                        "select rating_value from ratings where rating_id=(select max(rating_id) from ratings where track_id={0} and user_id={1})",
                        id, Db.UserId()), 0);
            App.Log.InfoFormat("Selected track {0} with rating {1} for user {2}", result.Id, result.Rating, Db.UserId());

            return result;
        }

        private static void SplitFolderIntoArtistAlbum(string folder, out string artist, out string album)
        {
            // No artist in MP3/MP4/M4A, get it from foldername (from pattern: anything\<artist>\<album>\track.mp3)
            artist = null;
            album = null;

            var folders = folder.Split('\\').ToList();
            if (folders.Count > 3)
            {
                album = folders[folders.Count - 2];
                artist = folders[folders.Count - 3];
            }
        }

        private static void RemoveYearOrTrack(ref string title)
        {
            // Remove the yeartrack indicator in titles like "01-The Ring" or "1973 - Queen"
            int pos = title.IndexOf("-");
            int value;
            if (pos >= 0 && pos < 7 && Int32.TryParse(title.Substring(0, pos).Trim(), out value))
            {
                title = title.Substring(pos + 1).Trim();
            }
        }

        public static string GetTitle(TagLib.File tagFile, string filename)
        {
            string result = tagFile.Tag.Title;
            if (result == null || result == "")
            {
                result = Path.GetFileNameWithoutExtension(filename);
                RemoveYearOrTrack(ref result);
            }
            return result;
        }

        public static string GetArtist(TagLib.File tagFile, string filename, bool albumOnly)
        {
            string result = tagFile.Tag.FirstAlbumArtist;
            if (String.IsNullOrWhiteSpace(result))
            {
                result = tagFile.Tag.FirstArtist;
                if (String.IsNullOrWhiteSpace(result))
                {
                    string album;
                    SplitFolderIntoArtistAlbum(filename, out result, out album);
                }
            }
            else if (! albumOnly)
            {
                // This is not for database storage, but just for display.
                // Database stores it by album-artist.

                string fa = tagFile.Tag.FirstArtist;
                if (! String.IsNullOrWhiteSpace(fa) && ! String.Equals(fa, result))
                {
                    if (fa.Contains(result))
                    {
                        // e.g. : result="Gare du Nord", fa= "My Artist; Gare du Nord", we don't want to repeat
                        result = fa;
                    }
                    else if (result.Contains(fa))
                    {
                        // e.g. : result= "My Artist; Gare du Nord", fa="Gare du Nord", result is OK now.
                    }
                    else
                    {
                        // e.g. : result = "Various Artists", fa="David Bowie", we make "David Bowie (Various Artists)"
                        result = fa + " (" + result + ")";
                    }
                }
            }

            return result;
        }

        public static string GetAlbum(TagLib.File tagFile, string filename)
        {
            string result = tagFile.Tag.Album;
            if (result == null || result == "")
            {
                string artist;
                SplitFolderIntoArtistAlbum(filename, out artist, out result);
                if (result.ToLowerInvariant().EndsWith("kbps"))
                {
                    // Remove the 320kbps indicator (or other)
                    int pos = result.LastIndexOf(' ');
                    int kbps;
                    if (Int32.TryParse(result.Substring(pos).ToLower().Replace("kbps", ""), out kbps))
                    {
                        result = result.Substring(0, pos);
                    }
                }
                RemoveYearOrTrack(ref result);
            }

            if (result != null)
            {
                int discNumber = (int)(tagFile.Tag.Disc > 0 ? tagFile.Tag.Disc : 1);
                // Enhance album title
                string redundantDisckPart = String.Format(" Disc {0}", discNumber);
                if (result.EndsWith(redundantDisckPart))
                {
                    result = result.Replace(redundantDisckPart, "");
                }
            }

            return result;
        }

    }
}
